// Copyright (c)  YISH. All rights reserved.
// Licensed under the MIT License. See License.txt in the project root for license information.

using System;
using System.Collections;
using System.Collections.Generic;
using NSQL.Expressions.Functions;

namespace NSQL.Expressions
{
    public class ExpressionChildrenVisitor : IExpressionVisitor<IEnumerable<IExpression>>
    {
        public static readonly ExpressionChildrenVisitor Instance = new ExpressionChildrenVisitor();
        
        IEnumerable<IExpression> IFunctionVisitor<IEnumerable<IExpression>>.Visit(ICountFunction expression)
        {
            yield return expression.Expr;
        }

        IEnumerable<IExpression> IFunctionVisitor<IEnumerable<IExpression>>.Visit(IRoundFunction expression)
        {
            yield return expression.Expr;
            yield return expression.Decimals;
        }

        IEnumerable<IExpression> IFunctionVisitor<IEnumerable<IExpression>>.Visit(ISumFunction expression)
        {
            yield return expression.Expr;
        }

        IEnumerable<IExpression> IFunctionVisitor<IEnumerable<IExpression>>.Visit(IMaxFunction expression)
        {
            yield return expression.Expr;
        }

        IEnumerable<IExpression> IFunctionVisitor<IEnumerable<IExpression>>.Visit(IAvgFunction expression)
        {
            yield return expression.Expr;
        }

        IEnumerable<IExpression> IFunctionVisitor<IEnumerable<IExpression>>.Visit(IMinFunction expression)
        {
            yield return expression.Expr;
        }

        IEnumerable<IExpression> IFunctionVisitor<IEnumerable<IExpression>>.Visit(IMedianFunction expression)
        {
            yield return expression.Expr;
        }

        IEnumerable<IExpression> IFunctionVisitor<IEnumerable<IExpression>>.Visit(IStdDevFunction expression)
        {
            yield return expression.Expr;
        }

        IEnumerable<IExpression> IFunctionVisitor<IEnumerable<IExpression>>.Visit(IVarianceFunction expression)
        {
            yield return expression.Expr;
        }

        IEnumerable<IExpression> IFunctionVisitor<IEnumerable<IExpression>>.Visit(IToCharFunction expression)
        {
            
            yield return expression.Expr;
            yield return expression.Formatter;
        }

        IEnumerable<IExpression> IFunctionVisitor<IEnumerable<IExpression>>.Visit(ITrimFunction expression)
        {
            yield return expression.Expr;
            yield return expression.TrimExpr;
        }

        IEnumerable<IExpression> IFunctionVisitor<IEnumerable<IExpression>>.Visit(ILengthFunction expression)
        {
            yield return expression.Expr;
        }

        IEnumerable<IExpression> IFunctionVisitor<IEnumerable<IExpression>>.Visit(ICastFunction expression)
        {
            yield return expression.Expr;
        }

        IEnumerable<IExpression> IFunctionVisitor<IEnumerable<IExpression>>.Visit(IToNumberFunction expression)
        {
            yield return expression.Text;
            yield return expression.Format;
        }

        IEnumerable<IExpression> IFunctionVisitor<IEnumerable<IExpression>>.Visit(ISubStringFunction expression)
        {
            yield return expression.Text;
            yield return expression.Position;
            yield return expression.Length;
        }

        IEnumerable<IExpression> IFunctionVisitor<IEnumerable<IExpression>>.Visit(INvlFunction expression)
        {
            yield return expression.Expr;
            yield return expression.Default;
            yield return expression.Then;
        }

        IEnumerable<IExpression> IFunctionVisitor<IEnumerable<IExpression>>.Visit(IPadFunction expression)
        {
            yield return expression.Text;
            yield return expression.PaddingText;
            yield return expression.Length;
        }

        IEnumerable<IExpression> IFunctionVisitor<IEnumerable<IExpression>>.Visit(ILeftFunction expression)
        {
            yield return expression.Text;
            yield return expression.Length;
        }

        IEnumerable<IExpression> IFunctionVisitor<IEnumerable<IExpression>>.Visit(IRightFunction expression)
        {
            yield return expression.Text;
            yield return expression.Length;
        }

        IEnumerable<IExpression> IFunctionVisitor<IEnumerable<IExpression>>.Visit(IUpperFunction expression)
        {
            yield return expression.Text;
        }

        IEnumerable<IExpression> IFunctionVisitor<IEnumerable<IExpression>>.Visit(ILowerFunction expression)
        {
            yield return expression.Text;
        }

        IEnumerable<IExpression> IFunctionVisitor<IEnumerable<IExpression>>.Visit(IReplaceFunction expression)
        {
            yield return expression.Text;
            yield return expression.OldValue;
            yield return expression.NewValue;
        }

        IEnumerable<IExpression> IFunctionVisitor<IEnumerable<IExpression>>.Visit(IExtractFunction expression)
        {
            yield return expression.DateTime;
        }

        IEnumerable<IExpression> IFunctionVisitor<IEnumerable<IExpression>>.Visit(IConcatFunction expression)
        {
            return expression.Items;
        }

        IEnumerable<IExpression> IFunctionVisitor<IEnumerable<IExpression>>.Visit(IReverseFunction expression)
        {
            yield return expression.Expr;
        }

        IEnumerable<IExpression> IFunctionVisitor<IEnumerable<IExpression>>.Visit(IToDatetimeFunction expression)
        {
            yield return expression.Format;
        }

        IEnumerable<IExpression> IFunctionVisitor<IEnumerable<IExpression>>.Visit(IAddIntervalFunction expression)
        {
            yield return expression.DateTime;
            yield return expression.Interval;
        }

        IEnumerable<IExpression> IFunctionVisitor<IEnumerable<IExpression>>.Visit(IStartWithFunction expression)
        {
            yield return expression.Expr;
            yield return expression.Pattern;
        }

        IEnumerable<IExpression> IFunctionVisitor<IEnumerable<IExpression>>.Visit(IEndWithFunction expression)
        {
            yield return expression.Expr;
            yield return expression.Pattern;
        }

        IEnumerable<IExpression> IFunctionVisitor<IEnumerable<IExpression>>.Visit(IContainsFunction expression)
        {
            yield return expression.Expr;
            yield return expression.Pattern;
        }

        IEnumerable<IExpression> IFunctionVisitor<IEnumerable<IExpression>>.Visit(ISinFunction expression)
        {
            yield return expression.Expr;
        }

        IEnumerable<IExpression> IFunctionVisitor<IEnumerable<IExpression>>.Visit(ICosFunction expression)
        {
            yield return expression.Expr;
        }

        IEnumerable<IExpression> IFunctionVisitor<IEnumerable<IExpression>>.Visit(ITanFunction expression)
        {
            yield return expression.Expr;
        }

        IEnumerable<IExpression> IFunctionVisitor<IEnumerable<IExpression>>.Visit(IAbsFunction expression)
        {
            yield return expression.Expr;
        }

        IEnumerable<IExpression> IFunctionVisitor<IEnumerable<IExpression>>.Visit(ISignFunction expression)
        {
            yield return expression.Expr;
        }

        IEnumerable<IExpression> IFunctionVisitor<IEnumerable<IExpression>>.Visit(ISqrtFunction expression)
        {
            yield return expression.Expr;
        }

        IEnumerable<IExpression> IFunctionVisitor<IEnumerable<IExpression>>.Visit(ILogFunction expression)
        {
            yield return expression.Base;
            yield return expression.Number;
        }

        IEnumerable<IExpression> IFunctionVisitor<IEnumerable<IExpression>>.Visit(IPowFunction expression)
        {
            yield return expression.X;
            yield return expression.Y;
        }

        IEnumerable<IExpression> IFunctionVisitor<IEnumerable<IExpression>>.Visit(IRankFunction expression)
        {
            yield return expression.Expr;
        }

        IEnumerable<IExpression> IFunctionVisitor<IEnumerable<IExpression>>.Visit(ICoalesceFunction expression)
        {
            return expression.Items;
        }

        IEnumerable<IExpression> IFunctionVisitor<IEnumerable<IExpression>>.Visit(IDecodeFunction expression)
        {
            return expression.Items;
        }

        IEnumerable<IExpression> IFunctionVisitor<IEnumerable<IExpression>>.Visit(ICeilFunction expression)
        {
            yield return expression.Expr;
        }

        IEnumerable<IExpression> IFunctionVisitor<IEnumerable<IExpression>>.Visit(IFloorFunction expression)
        {
            yield return expression.Expr;
        }

        IEnumerable<IExpression> IFunctionVisitor<IEnumerable<IExpression>>.Visit(IPercentileFunction expression)
        {
            yield return expression.Expr;
        }

        IEnumerable<IExpression> IFunctionVisitor<IEnumerable<IExpression>>.Visit(IFormatFunction expression)
        {
            yield return expression.Format;
            yield return expression.Items;
        }

        IEnumerable<IExpression> IFunctionVisitor<IEnumerable<IExpression>>.Visit(IDiffFunction expression)
        {
            yield return expression.Start;
            yield return expression.End;
        }

        IEnumerable<IExpression> IExpressionVisitor<IEnumerable<IExpression>>.Visit(IComparisonExpression expression)
        {
            yield return expression.Left;
            yield return expression.Right;
        }

        IEnumerable<IExpression> IExpressionVisitor<IEnumerable<IExpression>>.Visit(IColumnExpression expression)
        {
            return Array.Empty<IExpression>();
        }

        IEnumerable<IExpression> IExpressionVisitor<IEnumerable<IExpression>>.Visit(IConstantExpression expression)
        {
            return Array.Empty<IExpression>();
        }

        IEnumerable<IExpression> IExpressionVisitor<IEnumerable<IExpression>>.Visit(IInExpression expression)
        {
            yield return expression.Left;
            foreach (var expressionElement in expression.Elements)
            {
                yield return expressionElement;
            }
        }

        IEnumerable<IExpression> IExpressionVisitor<IEnumerable<IExpression>>.Visit(INotInExpression expression)
        {
            yield return expression.Left;
            foreach (var expressionElement in expression.Elements)
            {
                yield return expressionElement;
            }
        }

        IEnumerable<IExpression> IExpressionVisitor<IEnumerable<IExpression>>.Visit(ILogicalExpression expression)
        {
            yield return expression.Left;
            yield return expression.Right;
        }

        IEnumerable<IExpression> IExpressionVisitor<IEnumerable<IExpression>>.Visit(IBetweenExpression expression)
        {
            yield return expression.Left;
            yield return expression.Begin;
            yield return expression.End;
        }

        IEnumerable<IExpression> IExpressionVisitor<IEnumerable<IExpression>>.Visit(INotExpression expression)
        {
            yield return expression.Expr;
        }

        IEnumerable<IExpression> IExpressionVisitor<IEnumerable<IExpression>>.Visit(INullExpression expression)
        {
            yield return expression.Expr;
        }

        IEnumerable<IExpression> IExpressionVisitor<IEnumerable<IExpression>>.Visit(INotNullExpression expression)
        {
            yield return expression.Expr;
        }

        IEnumerable<IExpression> IExpressionVisitor<IEnumerable<IExpression>>.Visit(IMatchExpression expression)
        {
            yield return expression.Default;
            foreach (var expressionMatch in expression.Matches)
            {
                yield return expressionMatch.When;
                yield return expressionMatch.Then;
            }
        }

        IEnumerable<IExpression> IExpressionVisitor<IEnumerable<IExpression>>.Visit(ISimpleMatchExpression expression)
        {
            yield return expression.Default;
            yield return expression.Comparison;
            
            foreach (var expressionMatch in expression.Matches)
            {
                yield return expressionMatch.When;
                yield return expressionMatch.Then;
            }
        }

        IEnumerable<IExpression> IExpressionVisitor<IEnumerable<IExpression>>.Visit(IArithmeticExpression expression)
        {
            yield return expression.Left;
            yield return expression.Right;
        }

        IEnumerable<IExpression> IExpressionVisitor<IEnumerable<IExpression>>.Visit(IUnaryExpression expression)
        {
            yield return expression.Expr;
        }

        IEnumerable<IExpression> IExpressionVisitor<IEnumerable<IExpression>>.Visit(ISystemVariable expression)
        {
            return Array.Empty<IExpression>();
        }

        IEnumerable<IExpression> IExpressionVisitor<IEnumerable<IExpression>>.Visit(ILikeExpression expression)
        {
            yield return expression.Left;
            yield return expression.Pattern;
        }

        IEnumerable<IExpression> IExpressionVisitor<IEnumerable<IExpression>>.Visit(IExpressions expression)
        {
            return expression;
        }

        IEnumerable<IExpression> IExpressionVisitor<IEnumerable<IExpression>>.Visit(IExistsExpression expression)
        {
            throw new NotImplementedException();
        }

        IFunctionVisitor<IEnumerable<IExpression>> IExpressionVisitor<IEnumerable<IExpression>>.FunctionVisitor => this;
    }
}